package com.zzf.concurrent.example.communication;

import com.zzf.concurrent.example.util.TimeUtil;
import lombok.extern.slf4j.Slf4j;

import java.util.stream.Stream;

/**
 * @author GaoFeng2017
 * @date 2019/8/6 10:40
 */
@Slf4j
public class ProducerConsumerV2 {

    private int index = 0;

    private boolean isProduce = true;

    private final Object LOCK = new Object();

    public static void main(String[] args) {
        // singleTest();
        multiTest();
    }

    private static void singleTest() {
        ProducerConsumerV2 pc = new ProducerConsumerV2();
        new Thread() {
            @Override
            public void run() {
                while(true) {
                    pc.produce();
                    TimeUtil.sleep(10);
                }
            }
        }.start();

        new Thread() {
            @Override
            public void run() {
                while(true) {
                    pc.consume();
                    TimeUtil.sleep(10);
                }
            }
        }.start();
    }

    private static void multiTest() {
        ProducerConsumerV2 pc = new ProducerConsumerV2();
        Stream.of("P1", "P2", "P3").forEach(name -> {
            new Thread(name) {
                @Override
                public void run() {
                    while(true) {
                        pc.produce();
                        TimeUtil.sleep(1000);
                    }
                }
            }.start();
        });

        Stream.of("C1", "C2", "C3", "C4", "C5").forEach(name -> {
            new Thread(name) {
                @Override
                public void run() {
                    while(true) {
                        pc.consume();
                        TimeUtil.sleep(1000);
                    }
                }
            }.start();
        });
    }

    public void produce() {
        synchronized (LOCK) {

            // while解决重复消费的问题
            // 为什么不用if-else?
            while (!isProduce) {
                try {
                    // 消费者还未消费，等待
                    LOCK.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            // 生产
            index++;
            log.info("{}开始生产 -> {}", Thread.currentThread().getName(), index);
            // 唤醒消费者
            LOCK.notifyAll();
            // 被唤醒，改变生产状态
            this.isProduce = false;

        }
    }

    public void consume() {
        synchronized (LOCK) {

            while (isProduce) {
                try {
                    LOCK.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            // 消费
            log.info("{}开始消费 -> {}", Thread.currentThread().getName(), index);
            // 唤醒生产者
            LOCK.notifyAll();
            // 被唤醒，改变生产状态
            this.isProduce = true;
            // log.info("{}被唤醒", Thread.currentThread().getName());
        }
    }


}
